package com.qianfeng.smartdevices.websocket.handler;


//
//                            _ooOoo_  
//                           o8888888o  
//                           88" . "88  
//                           (| -_- |)  
//                            O\ = /O  
//                        ____/`---'\____  
//                      .   ' \\| |// `.  
//                       / \\||| : |||// \  
//                     / _||||| -:- |||||- \  
//                       | | \\\ - /// | |  
//                     | \_| ''\---/'' | |  
//                      \ .-\__ `-` ___/-. /  
//                   ___`. .' /--.--\ `. . __  
//                ."" '< `.___\_<|>_/___.' >'"".  
//               | | : `- \`.;`\ _ /`;.`/ - ` : | |  
//                 \ \ `-. \_ __\ /__ _/ .-` / /  
//         ======`-.____`-.___\_____/___.-`____.-'======  
//                            `=---='  
//  
//         .............................................  
//                  佛祖镇楼            BUG辟易  
//          佛曰:  
//                  写字楼里写字间，写字间里程序员；  
//                  程序人员写程序，又拿程序换酒钱。  
//                  酒醒只在网上坐，酒醉还来网下眠；  
//                  酒醉酒醒日复日，网上网下年复年。  
//                  但愿老死电脑间，不愿鞠躬老板前；  
//                  奔驰宝马贵者趣，公交自行程序员。  
//                  别人笑我忒疯癫，我笑自己命太贱；  


import com.qianfeng.smartdevices.event.BaseCommandEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by jackiechan on 2021/10/14 15:53
 *
 * @author jackiechan
 * @version 1.0
 * @since 1.0
 */
@Component

public class BaseControllHandler<E extends BaseCommandEvent> extends TextWebSocketHandler {

    private Map<Object,WebSocketSession> allClients = new HashMap<>();//保存所有会话的 map, key就是定位用户的关键数据,value 就是会话


    private ApplicationContext context;

    public Map<Object, WebSocketSession> getAllClients() {
        return allClients;
    }

    public ApplicationContext getContext() {
        return context;
    }

    @Autowired
    public void setContext(ApplicationContext context) {
        this.context = context;
    }

    /**
     * 连接连接之后执行,观察者模式,主要目的是保存会话的
     * @param session 当前建立的会话
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //我们保存的时候需要一个 key,这 key 从哪得到,用户在请求服务器的时候应该会传递一些唯一性的数据过来, 我们只要想办法获取到就行了
        Object name = session.getAttributes().get("name");
        WebSocketSession socketSession = allClients.get(name);
        if (socketSession != null) {//移除之前的会话,主要是在断线重连的时候来使用
            try {
                socketSession.close();
                allClients.remove(name);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        System.err.println("颜色控制器建立 websocket 请求了,标识====>" + name);
        allClients.put(name, session);//以用户的唯一标识作为 key,将会话保存到了 map 中
        //获取离线的消息,发给对方
        onOpen(session);
    }

    /**
     * 收到文本消息的时候执行
     * @param session 发送消息的人是谁
     * @param message 发送的内容是什么
     * @throws Exception
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        System.err.println("收到颜色设备发来的信息:" + message.getPayload());
    }

    /**
     * 连接关闭之后执行
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        super.afterConnectionClosed(session, status);
        Object name = session.getAttributes().get("name");
        allClients.remove(name);
        onClose(session);
    }

    /**
     * 当业务中发送控制命令的事件的时候 会执行当前方法
     * @param event
     */
    @EventListener
    @Async//通过异步执行事件中的操作,因为命令可以发送失败,我们的业务只需要通知发送操作即可,就可以返回给客户端成功的结果
    public void onEvent(E event) throws IOException {
        System.err.println(Thread.currentThread().getName());
        String uuid = event.getUuid();//设备的唯一标识
        WebSocketSession socketSession = allClients.get(uuid);
        if (socketSession != null&&socketSession.isOpen()) {
            socketSession.sendMessage(new TextMessage(event.getCommand()));//发送数据
        }
    }

    /**
     * 我们的子类有可能会有一些单独的操作,这个操作不一定会执行,所以我们写了一个空的方法,需要的重写即可
     * @param session
     */
    protected void onOpen(WebSocketSession session) {

    }

    protected void onClose(WebSocketSession session) {

    }
}
